<?php
declare(strict_types=1);
namespace Service\VenderClient\FacePlus;
use Service\Code\Normal;
use Service\BaseService;
use Service\ExtraService\TaskWorker;

class FacePlusApi extends BaseService
{
    protected $config;
    protected $router = [
        'detect'             => 'https://api-cn.faceplusplus.com/facepp/v3/detect',//人脸检测 API
        'faceset_create'     => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/create',//创建人脸库 API
        'faceset_delete'     => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/delete',//删除人脸库 API
        'faceset_update'     => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/update',//更新人脸库 API
        'faceset_getfacesets'=> 'https://api-cn.faceplusplus.com/facepp/v3/faceset/getfacesets',//获取人脸库列表及信息 API
        'faceset_getdetail'  => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/getdetail',//获取人脸库信息 API
        'faceset_addface'    => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/addface',//添加人脸 API
        'faceset_removeface' => 'https://api-cn.faceplusplus.com/facepp/v3/faceset/removeface',//获取openid
        'search'             => 'https://api-cn.faceplusplus.com/facepp/v3/search',//人脸搜索 API，
        'ocridcard'          => 'https://api-cn.faceplusplus.com/cardpp/v1/ocridcard'//身份证识别
    ];
    
    public function __construct( array $configBody = [] )
    {
        $this->config = $configBody;
        if(empty($this->config['api_key'])||empty($this->config['api_secret'])){
            throw new \Exception('处理失败【FACE++未配置，请联系管理员配置】 ' );
        }
    }
    
    /**
     * 人脸检测,传入参数为图片的base64加密的二进制数据(如需增加其他检测数据返回,需增加return_attributes,逗号分隔)
     * @param type $param
     * @return type
     */
    public function faceCheck($param) {
        if(empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $data=[
            'image_base64'=>$param['image_base64'],
            'return_attributes'=>'facequality,beauty'
        ];
        $response=$this->execute('detect', $data);
        return $response;
    }
    
    /**
     * 创建人脸库,唯一标识必传tags必须为英文字母和数字
     * @param type $param
     * @return type
     */
    public function createFaceStorage($param) {
        if(empty($param['outer_id'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        $data=[
            'outer_id'=>$param['outer_id']
        ];
        if(isset($param['display_name'])){
            $data['display_name']=$param['display_name'];
        }
        if(isset($param['tags'])){
            $data['tags']=$param['tags'];
        }
        if(isset($param['face_tokens'])){
            $data['face_tokens']=$param['face_tokens'];
            $data['force_merge']=1;
        }
        if(isset($param['user_data'])){
            $data['user_data']=$param['user_data'];
        }
        $response=$this->execute('faceset_create', $data);
        return $response;
    }
    
    /**
     * 删除人脸库
     * @param type $param
     * @return type
     */
    public function delFaceStorage($param) {        
        if(empty($param['faceset_token'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        $data=[
            'faceset_token'=>$param['faceset_token']
        ];
        if(isset($param['check_empty'])){
            $data['check_empty']=$param['check_empty'];
        }
        $response=$this->execute('faceset_delete', $data);
        return $response;
    }
    
    /**
     * 更新人脸库(tags必须为英文字母和数字)
     * @param type $param
     * @return type
     */
    public function updateFaceStorage($param) {
        if(empty($param['faceset_token'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        $data=[
            'faceset_token'=>$param['faceset_token']
        ];
        if(isset($param['display_name'])){
            $data['display_name']=$param['display_name'];
        }
        if(isset($param['tags'])){
            $data['tags']=$param['tags'];
        }
        if(isset($param['new_outer_id'])){
            $data['new_outer_id']=$param['new_outer_id'];
        }
        if(isset($param['user_data'])){
            $data['user_data']=$param['user_data'];
        }
        if(count($data)==1){
            return Normal::returnCode(Normal::FAIL,'缺少更改的参数');
        }
        $response=$this->execute('faceset_update', $data);
        return $response;
    }
    
    /**
     * 获取人脸库列表
     * @param type $param
     * @return type
     */
    public function getFaceStorageList($param) {
        $data=[];
        if(isset($param['tags'])){
            $data['tags']=$param['tags'];
        }
        if(isset($param['start'])){
            $data['start']=$param['start'];
        }
        $response=$this->execute('faceset_getfacesets', $data);
        return $response;
    }
    /**
     * 获取人脸库详情
     * @param type $param
     * @return type
     */
    public function getFaceStorageDetail($param) {
        if(empty($param['faceset_token'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        $data=[
            'faceset_token'=>$param['faceset_token']
        ];
        if(isset($param['start'])){
            $data['start']=$param['start'];
        }
        $response=$this->execute('faceset_getdetail', $data);
        return $response;
    }
    
    /**
     * 添加人脸信息
     * @param type $param
     * @return type
     */
    public function addFace($param) {
        if(empty($param['faceset_token'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        if(empty($param['face_tokens'])){
            return Normal::returnCode(Normal::FAIL,'人脸信息必传');
        }
        $data=[
            'faceset_token'=>$param['faceset_token'],
            'face_tokens'=>$param['face_tokens']
        ];
        $response=$this->execute('faceset_addface', $data);
        return $response;
    }
    
    /**
     * 人脸库人脸搜索(单库)
     * @param type $param
     * @return type
     */
    public function search($param){
        if(empty($param['faceset_token'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        if(empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $data=[
            'faceset_token'=>$param['faceset_token'],
            'image_base64'=>$param['image_base64'],
        ];
        $response=$this->execute('search', $data);
        return $response;
    }
    
    /**
     * 人脸库人脸搜索(多库)
     * @param type $param
     * @return type
     */
    public function searchStorages($param){
        if(empty($param['faceset_tokens'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传');
        }
        if( !is_array($param['faceset_tokens'])){
            return Normal::returnCode(Normal::FAIL,'图片库唯一标识必传类型错误');
        }
        if(empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $data=[];
        foreach ($param['faceset_tokens'] as $key => $value) {
            $data[]=[
                'faceset_token'=>$value,
                'image_base64'=>$param['image_base64'],
            ];
        }
        $response=$this->executeDatas('search', $data);          
        if($response['code']!= Normal::SUC){
            return $response;
        }
        $score=[];
        $scoredata=[];
        $errmsg='';
        foreach ($response['data'] as $key => $value) {
            $current=json_decode($value['response']['result'],true);
            if(isset($current['error_message'])){
                $errmsg=$current['error_message'];
                return Normal::returnCode(Normal::FAIL,$errmsg);
            }
            if(!isset($current['faces'])||empty($current['faces'])){
                return Normal::returnCode(Normal::FAIL,'传入图片未检测到人脸');
            }
            if(isset($current['results'][0]['confidence'])&& $current['results'][0]['confidence']>$current['thresholds']['1e-5']){
                $currentScore=$current['results'][0]['confidence'];
                $currentFace=$current['results'][0]['face_token'];
                $score[]=$currentScore;
                $scoredata[(string)$currentScore]=$currentFace;
            }
        }
        if(empty($score)){
            return Normal::returnCode(Normal::FAIL,'未搜索到相关信息');
        }
        return Normal::returnCode(Normal::SUC,'成功',['score'=>$score,'scoredata'=>$scoredata]);
    }
    
    /**
     * 身份证识别
     * @param type $param
     * @return type
     */
    public function ocridcard($param) {
        if(empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $data=[
            'image_base64'=>$param['image_base64'],
            'legality'=>1
        ];
        $response=$this->execute('ocridcard', $data);
        return $response;
        
    }
    
    public function execute(string $method, array $data){
        $sercertdata=[
            'api_key'=> $this->config['api_key'],
            'api_secret'=> $this->config['api_secret'],
        ];
        $postdata= array_merge($sercertdata,$data);
        $parameter = [
            [
                'tag'       => 'faceplus_'.$method,
                'url'       => $this->router[$method],
                'data'      => $postdata,
                'method'    => 'post',
                'format'    => 'x-www-form-urlencoded',
                'header'    => [
                ],
            ],
        ];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $response   = @json_decode($resTask['response']['result'],true);
        if(isset($response['error_message'])&&$response['error_message']!=''){
            return Normal::returnCode(Normal::FAIL,$response['error_message'],$response);
        }
        return Normal::returnCode(Normal::SUC,"请求成功",$response);
    }
    
    public function executeDatas(string $method, array $data){
        $sercertdata=[
            'api_key'=> $this->config['api_key'],
            'api_secret'=> $this->config['api_secret'],
        ];
        $parameter=[];
        foreach ($data as $key => $value) {
            if($value){
                $postdata=array_merge($sercertdata,$value);
                $parameter[]=[
                    'tag'       => 'faceplus_'.$method,
                    'url'       => $this->router[$method],
                    'data'      => $postdata,
                    'method'    => 'post',
                    'format'    => 'x-www-form-urlencoded',
                    'header'    => [
                    ],
                ];
            }
        }
        if(empty($parameter)){
            return Normal::returnCode(Normal::FAIL,"请求数据错误");
        }
        $resTask    = TaskWorker::instance()->addTask($parameter);
        return Normal::returnCode(Normal::SUC,"请求成功",$resTask);
    }
}
